package nl.cypherpunk.statefuzzer.fuzzing;

import net.automatalib.words.Alphabet;
import net.automatalib.words.Word;
import nl.cypherpunk.statefuzzer.LearningConfig;
import nl.cypherpunk.statefuzzer.mealyDot.MealyDot;
import nl.cypherpunk.statefuzzer.mealyDot.MealyState;
import nl.cypherpunk.statefuzzer.mealyDot.OutputTransition;
import nl.cypherpunk.statefuzzer.smtp.SMTPSUL;
import static nl.cypherpunk.statefuzzer.Common.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class FuzzingBlackbox {
    MealyDot mealyAutoamta;
    MealyState initialState;
    MealyState sinkedState;
    Random rand = new Random();
    Alphabet<String> alphabet;
    Alphabet<String> meaning;
    SUT<String,String> sut;
    Map<String, LinkedHashMap<byte[], Double>> seed;
    LinkedHashMap<Integer, List<byte[]>> standardValue;
    PrintStream log;
    String server_output;
    String Seed;
    String Crash;
    String Message;
    String seed_dir;
    boolean isCrash;
    int initCoverage = 0;
    int total_num = 0;
    int havoc_num = 50;
    boolean ROLE_CLIENT = false;
    ArrayList<byte[]> messagePool;
    ArrayList<Double> messageScore;
    ArrayList<List<byte[]>> seedPool;
    ArrayList<Double> seedScore;
    int prevCoverage;
    int start;
    int end;
    ArrayList<FuzzingPath> statePool;
    ArrayList<Double> stateScore;
    ArrayList<byte[]> dict;

    byte[] interesting_8 = {-128, 01, 127};
    Integer[] interesting_16 = {-32768, -129, 32767};
    Integer[] interesting_32 = {-2147483648, -100663046, -32769, 100663045, 2147483647};
    public FuzzingBlackbox(LearningConfig config, String dotFileName, SUT sut, Alphabet<String> inputAlphabet) throws Exception {
        mealyAutoamta = new MealyDot(dotFileName);
        initialState = mealyAutoamta.getInitialState();
        sinkedState = mealyAutoamta.getSinkedState();
        this.sut = sut;
        this.alphabet = inputAlphabet;
        this.server_output = config.output_dir + File.separator + "server.log";
        File serverLog = new File(this.server_output);
        this.Seed = config.output_dir + File.separator + "Seed";
        this.Crash= config.output_dir + File.separator + "Crash";
        this.Message = config.output_dir + File.separator + "Message";
        File outputDir = new File(Seed);
        outputDir.mkdirs();
        File crashDir = new File(Crash);
        crashDir.mkdirs();
        File messageDir = new File(Message);
        messageDir.mkdirs();
        seed_dir = config.seed_dir;
        standardValue = new LinkedHashMap<>();
        statePool = new ArrayList<>();
        stateScore = new ArrayList<>();
        dict = new ArrayList<>();
        seed = new HashMap<>();
        prevCoverage = 0;
        for (int i = 0; i < alphabet.size(); i++) {
            seed.put(alphabet.getSymbol(i), new LinkedHashMap<>());
        }
        isCrash = false;
        File outputFile = new File(config.output_dir, "fuzzing.log");
        log = new PrintStream(outputFile);
    }

    public void randomWalkWithFuzzing(int number, int time) throws Exception, IOException, ClassNotFoundException, InterruptedException {
        Date startDate = new Date();
        String timestamp = String.valueOf(startDate.getTime() / 1000);
        start = Integer.valueOf(timestamp);
        //Traverse all states based on depth-first strategy, and record the concrete messages of the set Q
        initCoverage = 100;
        //initStandard();
        prevCoverage = initCoverage;
        int num = number;
        this.sut.pre();
        //based on the seeds
        //read the seed files
        seedPool = new ArrayList<>();
        seedScore = new ArrayList<>();
        messagePool = new ArrayList<>();
        messageScore = new ArrayList<>();
        readFromFile(seedPool ,seedScore, this.seed_dir);
        dictFromFile("dict");
        int j = 0;
        int i = 0;
        System.out.println("State fuzzing");

        for(int stateIndex = statePool.size()-1; stateIndex > -1; stateIndex--)
        {
            int exec_num = 0;
            int m = 0;
            byte[] message;
            FuzzingPath curPath = statePool.get(stateIndex);
            System.out.println(stateIndex);
            for(int mutateIndex = 0; mutateIndex < curPath.messages.size(); mutateIndex++) {
                List<byte[]> currentSeed = deepCopy(curPath.messages);
                List<byte[]> interesting;
                if (!standardValue.containsKey(byteToHex(currentSeed.get(mutateIndex)).hashCode())) {
                    interesting = new ArrayList<>();
                    for (j = 0; j < currentSeed.get(mutateIndex).length; j++) {
                        this.sut.pre();
                        List<byte[]> mutateSeed = new ArrayList<>();
                        m = 0;
                        isCrash = false;
                        for (; m < currentSeed.size(); m++) {
                            String output = null;
                            if (m == mutateIndex) {
                                //mutate the mth package
                                message = new byte[currentSeed.get(m).length];
                                System.arraycopy(currentSeed.get(m), 0, message, 0, currentSeed.get(m).length);
                                message[j] ^= 0xFF;
                                output = sut.SendFuzzingMessage(message);
                                mutateSeed.add(message);
                            } else {
                                output = sut.SendFuzzingMessage(currentSeed.get(m));
                                mutateSeed.add(currentSeed.get(m));
                            }
                            if (output.contains("Closed"))
                                break;
                        }
                        total_num++;
                        curPath.fuzzs++;
                        this.sut.post();
                        calculateScore(mutateSeed, Math.min(mutateIndex, mutateSeed.size() - 1), 1);
                    }
                    /*for (j = 0; j < currentSeed.get(mutateIndex).length; j++) {
                        for(i = 0; i < interesting_8.length; i++) {
                            this.sut.pre();
                            List<byte[]> mutateSeed = new ArrayList<>();
                            m = 0;
                            isCrash = false;
                            for (; m < currentSeed.size(); m++) {
                                String output = null;
                                if (m == mutateIndex) {
                                    //mutate the mth package
                                    message = new byte[currentSeed.get(m).length];
                                    System.arraycopy(currentSeed.get(m), 0, message, 0, currentSeed.get(m).length);
                                    message[j] = interesting_8[i];
                                    output = sut.SendFuzzingMessage(message);
                                    mutateSeed.add(message);
                                } else {
                                    output = sut.SendFuzzingMessage(currentSeed.get(m));
                                    mutateSeed.add(currentSeed.get(m));
                                }
                                if (output.contains("Closed"))
                                    break;
                            }
                            total_num++;
                            curPath.fuzzs++;
                            this.sut.post();
                            if (calculateScore(mutateSeed, Math.min(mutateIndex, mutateSeed.size() - 1), 1)) {
                                curPath.coverageAdd++;
                                curPath.score++;
                                stateScore.set(stateIndex, curPath.score + curPath.coverageAdd * (Math.ceil((end - start) / 600.0)) - curPath.fuzzs / 100.0);
                                interesting.add(mutateSeed.get(Math.min(mutateIndex, mutateSeed.size() - 1)));
                                curPath.addMessages(mutateSeed, 1.0 * (mutateIndex + 1) * Math.ceil((end - start) / 600.0) * 1);
                            }
                        }
                    }
                    for (j = 0; j < currentSeed.get(mutateIndex).length-1; j++) {
                        for(i = 0; i < interesting_16.length; i++) {
                            this.sut.pre();
                            List<byte[]> mutateSeed = new ArrayList<>();
                            m = 0;
                            isCrash = false;
                            for (; m < currentSeed.size(); m++) {
                                String output = null;
                                if (m == mutateIndex) {
                                    //mutate the mth package
                                    message = new byte[currentSeed.get(m).length];
                                    System.arraycopy(currentSeed.get(m), 0, message, 0, currentSeed.get(m).length);
                                    message[j] = intToByteArray(interesting_16[i])[3];
                                    message[j+1] = intToByteArray(interesting_16[i])[2];
                                    output = sut.SendFuzzingMessage(message);
                                    mutateSeed.add(message);
                                } else {
                                    output = sut.SendFuzzingMessage(currentSeed.get(m));
                                    mutateSeed.add(currentSeed.get(m));
                                }
                                if (output.contains("Closed"))
                                    break;
                            }
                            total_num++;
                            curPath.fuzzs++;
                            this.sut.post();
                            if (calculateScore(mutateSeed, Math.min(mutateIndex, mutateSeed.size() - 1), 1)) {
                                curPath.coverageAdd++;
                                curPath.score++;
                                stateScore.set(stateIndex, curPath.score + curPath.coverageAdd * (Math.ceil((end - start) / 600.0)) - curPath.fuzzs / 100.0);
                                interesting.add(mutateSeed.get(Math.min(mutateIndex, mutateSeed.size() - 1)));
                                curPath.addMessages(mutateSeed, 1.0 * (mutateIndex + 1) * Math.ceil((end - start) / 600.0) * 1);
                            }
                        }
                    }
                    for (j = 0; j < currentSeed.get(mutateIndex).length-4; j++) {
                        for(i = 0; i < interesting_32.length; i++) {
                            this.sut.pre();
                            List<byte[]> mutateSeed = new ArrayList<>();
                            m = 0;
                            isCrash = false;
                            for (; m < currentSeed.size(); m++) {
                                String output = null;
                                if (m == mutateIndex) {
                                    //mutate the mth package
                                    message = new byte[currentSeed.get(m).length];
                                    System.arraycopy(currentSeed.get(m), 0, message, 0, currentSeed.get(m).length);
                                    message[j] = intToByteArray(interesting_32[i])[3];
                                    message[j+1] = intToByteArray(interesting_32[i])[2];
                                    message[j+2] = intToByteArray(interesting_32[i])[1];
                                    message[j+3] = intToByteArray(interesting_32[i])[0];
                                    output = sut.SendFuzzingMessage(message);
                                    mutateSeed.add(message);
                                } else {
                                    output = sut.SendFuzzingMessage(currentSeed.get(m));
                                    mutateSeed.add(currentSeed.get(m));
                                }
                                if (output.contains("Closed"))
                                    break;
                            }
                            total_num++;
                            curPath.fuzzs++;
                            this.sut.post();
                            if (calculateScore(mutateSeed, Math.min(mutateIndex, mutateSeed.size() - 1), 1)) {
                                curPath.coverageAdd++;
                                curPath.score++;
                                stateScore.set(stateIndex, curPath.score + curPath.coverageAdd * (Math.ceil((end - start) / 600.0)) - curPath.fuzzs / 100.0);
                                interesting.add(mutateSeed.get(Math.min(mutateIndex, mutateSeed.size() - 1)));
                                curPath.addMessages(mutateSeed, 1.0 * (mutateIndex + 1) * Math.ceil((end - start) / 600.0) * 1);
                            }
                        }
                    }*/
                }
                else
                {
                    interesting = standardValue.get(byteToHex(currentSeed.get(mutateIndex)).hashCode());
                    for (j = 0; j < interesting.size(); j++) {
                        this.sut.pre();
                        List<byte[]> mutateSeed = new ArrayList<>();
                        m = 0;
                        isCrash = false;
                        for (; m < currentSeed.size(); m++) {
                            String output = null;
                            if (m == mutateIndex) {
                                //mutate the mth package
                                message = new byte[interesting.get(j).length];
                                System.arraycopy(interesting.get(j), 0, message, 0, interesting.get(j).length);
                                output = sut.SendFuzzingMessage(message);
                                mutateSeed.add(message);
                            } else {
                                output = sut.SendFuzzingMessage(currentSeed.get(m));
                                mutateSeed.add(currentSeed.get(m));
                            }
                            if (output.contains("Closed"))
                                break;
                        }
                        total_num++;
                        curPath.fuzzs++;
                        this.sut.post();
                        calculateScore(mutateSeed, Math.min(mutateIndex, mutateSeed.size() - 1), 1);
                    }
                }

                //RANDOM HAVO
                //SPLICING
                byte[] original = new byte[currentSeed.get(mutateIndex).length];
                System.arraycopy(currentSeed.get(mutateIndex), 0, original, 0, currentSeed.get(mutateIndex).length);
                //SPLICING
                for(int splice_index = 0;splice_index < 10; splice_index++) {
                    //mutate the mth package
                    if (splice_index < 1) {
                        message = new byte[original.length];
                        System.arraycopy(original, 0, message, 0, original.length);
                    } else {
                        message = new byte[original.length];
                        int fail = 0;
                        while (true) {
                            int messageIndex = rand.nextInt(messagePool.size());
                            byte[] message1 = new byte[messagePool.get(messageIndex).length];
                            System.arraycopy(messagePool.get(messageIndex), 0, message1, 0, messagePool.get(messageIndex).length);
                            System.arraycopy(original, 0, message, 0, original.length);
                            if (message.length < 5 || message1.length < 5)
                                break;
                            if (splice(message, message1,rand)) {
                                message = new byte[message1.length];
                                System.arraycopy(message1, 0, message, 0, message1.length);
                                break;
                            }
                            fail++;
                            if(fail>2)
                                break;
                        }
                    }
                    currentSeed.set(mutateIndex, message);
                    for (j = 0; j < 10; j++) {
                        this.sut.pre();
                        isCrash=false;
                        List<byte[]> mutateSeed = new ArrayList<>();
                        for (m = 0; m < currentSeed.size(); m++) {
                            String output = null;
                            if (m == mutateIndex) {
                                //mutate the mth package
                                int mutateNum = 5;
                                message = new byte[currentSeed.get(m).length];
                                System.arraycopy(currentSeed.get(m), 0, message, 0, currentSeed.get(m).length);
                                for (i = 0; i < mutateNum; i++) {
                                    int mutateStrategy = rand.nextInt(11);
                                    if (mutateStrategy < 5) {
                                        MutateMessage mutate = new MutateMessage(rand);
                                        while (mutate.newSize == 0)
                                            mutate.MutateDispatcher(message, message.length);
                                        message = new byte[mutate.newSize];
                                        System.arraycopy(mutate.newMessage, 0, message, 0, mutate.newSize);
                                    } else if (mutateStrategy == 5) {
                                        byte[] message1 = currentSeed.get(rand.nextInt(currentSeed.size()));
                                        byte[] message2 = new byte[message.length];
                                        System.arraycopy(message, 0, message2, 0, message.length);
                                        message = new byte[message2.length + message1.length];
                                        System.arraycopy(message1, 0, message, 0, message1.length);
                                        System.arraycopy(message2, 0, message, message1.length, message2.length);
                                    } else if (mutateStrategy == 6) {
                                        byte[] message1 = currentSeed.get(rand.nextInt(currentSeed.size()));
                                        byte[] message2 = new byte[message.length];
                                        System.arraycopy(message, 0, message2, 0, message.length);
                                        message = new byte[message2.length + message1.length];
                                        System.arraycopy(message2, 0, message, 0, message2.length);
                                        System.arraycopy(message1, 0, message, message2.length, message1.length);
                                    } else if (mutateStrategy == 7 && !messagePool.isEmpty()) {
                                        int messageIndex = rand.nextInt(messagePool.size());
                                        byte[] message1 = messagePool.get(messageIndex);
                                        message = new byte[message1.length];
                                        System.arraycopy(message1, 0, message, 0, message1.length);
                                    } else if (mutateStrategy == 8 && !messagePool.isEmpty()) {
                                        int messageIndex = rand.nextInt(messagePool.size());
                                        byte[] message1 = messagePool.get(messageIndex);
                                        byte[] message2 = new byte[message.length];
                                        System.arraycopy(message, 0, message2, 0, message.length);
                                        message = new byte[message2.length + message1.length];
                                        System.arraycopy(message2, 0, message, 0, message2.length);
                                        System.arraycopy(message1, 0, message, message2.length, message1.length);
                                    } else if (mutateStrategy == 9 && !messagePool.isEmpty()) {
                                        byte[] message2 = new byte[message.length];
                                        System.arraycopy(message, 0, message2, 0, message.length);
                                        message = new byte[2 * message2.length];
                                        System.arraycopy(message2, 0, message, 0, message2.length);
                                        System.arraycopy(message2, 0, message, message2.length, message2.length);
                                    } else if (mutateStrategy == 10 && dict.size() > 0) {
                                        byte[] message1 = dict.get(rand.nextInt(dict.size()));
                                        byte[] message2 = new byte[message.length];
                                        System.arraycopy(message, 0, message2, 0, message.length);
                                        message = new byte[message2.length + message1.length];
                                        int insert_at = rand.nextInt(message2.length);
                                        System.arraycopy(message2, 0, message, 0, insert_at);
                                        System.arraycopy(message1, 0, message, insert_at, message1.length);
                                        System.arraycopy(message2, insert_at, message, insert_at+message1.length, message2.length - insert_at);
                                    }
                                }
                                output = sut.SendFuzzingMessage(message);
                                mutateSeed.add(message);
                            } else {
                                output = sut.SendFuzzingMessage(currentSeed.get(m));
                                mutateSeed.add(currentSeed.get(m));
                            }
                            if (output.contains("Closed"))
                                break;
                        }
                        total_num++;
                        curPath.fuzzs++;
                        this.sut.post();
                        calculateScore(mutateSeed, Math.min(mutateIndex, mutateSeed.size() - 1), 1);
                    }
                }
                standardValue.put(byteToHex(original).hashCode(),interesting);
            }
        }
        log.println("Init : " + total_num);
        log.println("Init time: " + (end-start));
        System.out.println("Start random");
        boolean isAdded = false;
        while(true)
        {
            int stateIndex = rand.nextInt(statePool.size());
            FuzzingPath curPath = statePool.get(stateIndex);
            int loop = 0;
            while(curPath.messagesList.isEmpty()){
                stateIndex = rand.nextInt(statePool.size());
                curPath = statePool.get(stateIndex);
            }
            while(true) {
                loop ++;
                if(loop > 20)
                    break;
                this.sut.pre();
                isCrash = false;
                int seedIndex = rand.nextInt(curPath.messagesList.size());
                List<byte[]> currentSeed = deepCopy(curPath.messagesList.get(seedIndex));
                if (rand.nextInt(2) == 0) {
                    List<byte[]> currentSeed2 = deepCopy(seedPool.get(rand.nextInt(seedPool.size())));
                    currentSeed = currentSeed.subList(0, rand.nextInt(currentSeed.size()));
                    currentSeed2 = currentSeed2.subList(rand.nextInt(currentSeed2.size()), currentSeed2.size());
                    currentSeed.addAll(currentSeed2);
                }
                if (rand.nextInt(3) == 2)
                    Collections.shuffle(currentSeed);
                int mutateIndex = rand.nextInt(currentSeed.size());
                List<byte[]> mutateSeed = new ArrayList<>();
                for (int m = 0; m < currentSeed.size(); m++) {
                    String output = null;
                    byte[] message = new byte[currentSeed.get(m).length];
                    System.arraycopy(currentSeed.get(m), 0, message, 0, currentSeed.get(m).length);
                    if(m==mutateIndex){
                        int mutateNum = 5;
                        for (i = 0; i < mutateNum; i++) {
                            int mutateStrategy = rand.nextInt(12);
                            if (mutateStrategy < 5) {
                                MutateMessage mutate = new MutateMessage(rand);
                                while (mutate.newSize == 0)
                                    mutate.MutateDispatcher(message, message.length);
                                message = new byte[mutate.newSize];
                                System.arraycopy(mutate.newMessage, 0, message, 0, mutate.newSize);
                            }else if (mutateStrategy == 5) {
                                byte[] message1 = currentSeed.get(rand.nextInt(currentSeed.size()));
                                byte[] message2 = new byte[message.length];
                                System.arraycopy(message, 0, message2, 0, message.length);
                                message = new byte[message2.length + message1.length];
                                System.arraycopy(message1, 0, message, 0, message1.length);
                                System.arraycopy(message2, 0, message, message1.length, message2.length);
                            } else if (mutateStrategy == 6) {
                                byte[] message1 = currentSeed.get(rand.nextInt(currentSeed.size()));
                                byte[] message2 = new byte[message.length];
                                System.arraycopy(message, 0, message2, 0, message.length);
                                message = new byte[message2.length + message1.length];
                                System.arraycopy(message2, 0, message, 0, message2.length);
                                System.arraycopy(message1, 0, message, message2.length, message1.length);
                            } else if (mutateStrategy == 7 && !messagePool.isEmpty()) {
                                int messageIndex = rand.nextInt(messagePool.size());
                                byte[] message1 = messagePool.get(messageIndex);
                                message = new byte[message1.length];
                                System.arraycopy(message1, 0, message, 0, message1.length);
                            } else if (mutateStrategy == 8 && !messagePool.isEmpty()) {
                                int messageIndex = rand.nextInt(messagePool.size());
                                byte[] message1 = messagePool.get(messageIndex);
                                byte[] message2 = new byte[message.length];
                                System.arraycopy(message, 0, message2, 0, message.length);
                                message = new byte[message2.length + message1.length];
                                System.arraycopy(message2, 0, message, 0, message2.length);
                                System.arraycopy(message1, 0, message, message2.length, message1.length);
                            } else if (mutateStrategy == 9 && !messagePool.isEmpty()) {
                                byte[] message2 = new byte[message.length];
                                System.arraycopy(message, 0, message2, 0, message.length);
                                message = new byte[2 * message2.length];
                                System.arraycopy(message2, 0, message, 0, message2.length);
                                System.arraycopy(message2, 0, message, message2.length, message2.length);
                            } else if (mutateStrategy == 10 && dict.size() > 0) {
                                byte[] message1 = dict.get(rand.nextInt(dict.size()));
                                byte[] message2 = new byte[message.length];
                                System.arraycopy(message, 0, message2, 0, message.length);
                                message = new byte[message2.length + message1.length];
                                int insert_at = rand.nextInt(message2.length);
                                System.arraycopy(message2, 0, message, 0, insert_at);
                                System.arraycopy(message1, 0, message, insert_at, message1.length);
                                System.arraycopy(message2, insert_at, message, insert_at+message1.length, message2.length - insert_at);
                            } else {
                                byte[] message2 = new byte[message.length];
                                System.arraycopy(message, 0, message2, 0, message.length);
                                int fail = 0;
                                while (true) {
                                    int messageIndex = rand.nextInt(messagePool.size());
                                    byte[] message1 = new byte[messagePool.get(messageIndex).length];
                                    System.arraycopy(messagePool.get(messageIndex), 0, message1, 0, messagePool.get(messageIndex).length);
                                    System.arraycopy(message2, 0, message, 0, message2.length);
                                    if (message.length < 5 || message1.length < 5)
                                        break;
                                    if (splice(message2, message1,rand)) {
                                        message = new byte[message1.length];
                                        System.arraycopy(message1, 0, message, 0, message1.length);
                                        break;
                                    }
                                    fail++;
                                    if(fail>2)
                                        break;
                                }
                            }
                        }
                    }
                    output = sut.SendFuzzingMessage(message);
                    mutateSeed.add(message);
                    if (output.contains("Closed"))
                        break;
                }
                total_num++;
                this.sut.post();
                calculateScore(mutateSeed, Math.min(mutateIndex, mutateSeed.size() - 1), 1);

                Date endDate = new Date();
                String endstamp = String.valueOf(endDate.getTime() / 1000);
                end = Integer.valueOf(endstamp);
                if (end - start > time)
                    break;
            }

            Date endDate = new Date();
            String endstamp = String.valueOf(endDate.getTime() / 1000);
            end = Integer.valueOf(endstamp);
            if (end - start > time)
                break;
        }

        log.println("The execs done : " + total_num);
        log.println("The total time : " + (end - start));
        log.close();
        sut.exit();
    }

    public void setInputAlphabet(Alphabet<String> inputAlphabet) {
        this.alphabet = inputAlphabet;
    }

    public void readFromFile(ArrayList<List<byte[]>> seedPool, ArrayList<Double> seedScore,String dir)
    {
        List<String> files = new ArrayList<String>();
        File file = new File(dir);
        if(file.length()==0)
            return;
        File[] tempList = file.listFiles();
        List fileList = Arrays.asList(tempList);
        Collections.sort(fileList, new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
                if (o1.isDirectory() && o2.isFile())
                    return -1;
                if (o1.isFile() && o2.isDirectory())
                    return 1;
                return o1.getName().compareTo(o2.getName());
            }
        });
        for (int i = 0; i < tempList.length; i++) {
            if (tempList[i].isFile()) {
                files.add(tempList[i].toString());
                File temp = new File(tempList[i].toString());
                Double score = 10*1.0;
                try {
                    score = Double.parseDouble(tempList[i].toString().substring(tempList[i].toString().length() - 5, tempList[i].toString().length()));
                }
                catch (Exception e)
                {
                    score = 10*1.0;
                }
                try {
                    InputStream fileIn = new FileInputStream(temp);
                    //DataInputStream in = new DataInputStream(fileIn);

                    // 使用缓存区读入对象效率更快
                    BufferedInputStream in = new BufferedInputStream(fileIn);
                    byte[] len = new byte[1024] ;
                    int length;
                    List<byte[]> seed = new ArrayList<>();
                    Word<String> inputList = Word.epsilon();
                    List<MealyState> initList = new LinkedList<MealyState>();
                    initList.add(initialState);
                    while(in.read(len,0,4)!=-1)
                    {
                        length = byteArrayToInt(len);
                        byte[] bys = new byte[length];
                        in.read(bys,0,length);
                        seed.add(bys);
                        inputList.append(sut.messageToSymbol(bys));
                        messagePool.add(bys);
                        messageSave(bys, this.Message + File.separator + "Message" + String.format("%06d", total_num));
                        messageScore.add(score);
                    }
                    seedPool.add(seed);
                    seedScore.add(10.0);
                    FuzzingPath tmp = new FuzzingPath(initList,seed,inputList);
                    System.out.println(inputList);
                    tmp.addMessages(seed,0.0);
                    statePool.add(tmp);
                    stateScore.add(0.0);
                    in.close();
                    fileIn.close();
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }
                //文件名，不包含路径
                //String fileName = tempList[i].getName();

            }
        }
    }
    public void dictFromFile(String dictFile)
    {
        Double score = 10*1.0;
        try {
            BufferedReader br = new BufferedReader(new FileReader(dictFile));
            String keyword;
            int length;
            while((keyword=br.readLine())!=null)
            {
                dict.add(keyword.getBytes("US-ASCII"));
            }
            br.close();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    public void initStandard() throws IOException, ClassNotFoundException, InterruptedException
    {
        Queue<TransitionRecord> bfsQueue = new ArrayDeque<>();
        List<MealyState> initList = new LinkedList<MealyState>();
        initList.add(initialState);
        bfsQueue.add(new TransitionRecord(initialState,Word.epsilon(),Word.epsilon(), new LinkedList<byte[]>(),initList));
        TransitionRecord curr = bfsQueue.poll();
        int j = 0;

        String sinkedStateName="";
        if(sinkedState!=null)
            sinkedStateName = sinkedState.getName();
        while(curr != null)
        {
            MealyState currState = curr.state;
            for(int i = 0; i < currState.getInputs().size(); i++)
            {
                this.sut.pre();
                ArrayList<byte[]> testCase = new ArrayList<>();
                List<byte[]> messageList = deepCopy(curr.messageList);
                List<MealyState> stateList = deepCopy(curr.stateList);
                String input = currState.getInputs().get(i);
                OutputTransition outputTransition = currState.getOutputTransition(input);
                MealyState targetState = outputTransition.state;
                if(targetState != null ){
                    Iterator iter = curr.accessSequence.iterator();
                    while (iter.hasNext())
                    {
                        String tmpInput = iter.next().toString();
                        sut.step(tmpInput);
                    }
                    String output = sut.step(input);
                    sut.post();
                    if((stateContain(stateList,targetState) || targetState.getName().equals(sinkedStateName)) && !output.contains("ConnectionClosed"))
                    {
                        byte[] message = sut.getCurrent();
                        if(message != null)
                            messageList.add(message);
                        stateList.add(targetState);
                        Word<String> inputList = curr.accessSequence.append(input);
                        Word<String> outputList = curr.outputSequence.append(output);
                        FuzzingPath tmp = new FuzzingPath(stateList,messageList,inputList);
                        System.out.println(inputList);
                        tmp.addMessages(messageList,0.0);
                        statePool.add(tmp);
                        stateScore.add(0.0);
                        total_num++;
                        j++;
                    }
                    else if(!output.contains("ConnectionClosed"))
                    {
                        byte[] message = sut.getCurrent();
                        if(message != null)
                            messageList.add(message);
                        stateList.add(targetState);
                        Word<String> inputList = curr.accessSequence.append(input);
                        Word<String> outputList = curr.outputSequence.append(output);
                        TransitionRecord newRecord = new TransitionRecord(targetState,inputList,outputList,messageList,stateList);
                        total_num++;
                        j++;
                        bfsQueue.add(newRecord);
                    }
                }
            }
            curr = bfsQueue.poll();
        }
        bfsQueue.clear();
        bfsQueue = null;
    }

    public boolean stateContain(List<MealyState> stateList, MealyState targetState)
    {
        for (MealyState tmp : stateList ) {
            if(tmp.getName().equals(targetState.getName()))
                return true;
        }
        return false;
    }

    public boolean calculateScore(List<byte[]> mutateSeed, int mutateIndex, int weight) throws IOException{
        Date endDate = new Date();
        String endstamp = String.valueOf(endDate.getTime() / 1000);
        end = Integer.valueOf(endstamp);
        int coverage = this.sut.getCoverage();
        if (coverage == 1) {
            System.out.println("Crash");
            seedSave(mutateSeed, this.Crash  + File.separator + "Crash_" + String.format("%06d", total_num) + "_" + String.format("%05d", coverage));
            seedSave(mutateSeed, this.Seed  + File.separator + "Fuzzing" + String.format("%06d", total_num) + "_" + String.format("%05d", coverage));
            isCrash = true;
            return true;
        }
        if (coverage > prevCoverage) {
            if (coverage == 0)
                coverage = initCoverage;
            System.out.println(coverage);
            if (coverage > prevCoverage) {
                seedSave(mutateSeed, this.Seed + File.separator + "Fuzzing" + String.format("%06d", total_num) + "-" + String.format("%05d", coverage));
            }
            prevCoverage = coverage;
            return true;
        }
        return false;
    }

}
